package com.lzqinga.service;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.lzqinga.config.XfApiConfig;
import okhttp3.*;
import okio.ByteString;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * - @author lzqinga
 * - @description
 * - @date 2025/10/13/013 14:50
 **/
@Service
public class XxunFeiAIService extends WebSocketListener {

    @Autowired
    XfApiConfig xfApiConfig;

    private static final Gson gson = new Gson();
    private static final String HOST_URL = "https://cbm01.cn-huabei-1.xf-yun.com/v1/private/mcd9m97e6";

    // 发音人列表
    public enum VoiceType {
        LINGFEIYI("x5_lingfeiyi_flow", "凌菲菲"),
        XIAOYAN("xiaoyan", "小燕"),
        XIAOFENG("xiaofeng", "小峰");

        private final String code;
        private final String name;

        VoiceType(String code, String name) {
            this.code = code;
            this.name = name;
        }

        public String getCode() { return code; }
        public String getName() { return name; }
    }

    // 合成参数配置
    public static class TtsConfig {
        private VoiceType voiceType = VoiceType.LINGFEIYI;
        private int speed = 50;        // 语速 0-100
        private int volume = 50;       // 音量 0-100
        private int pitch = 50;        // 音高 0-100
        private String audioFormat = "lame"; // 音频格式: raw, lame
        private int sampleRate = 24000; // 采样率

        public TtsConfig() {}

        public TtsConfig(VoiceType voiceType, int speed, int volume, int pitch) {
            this.voiceType = voiceType;
            this.speed = speed;
            this.volume = volume;
            this.pitch = pitch;
        }

        // getters and setters
        public VoiceType getVoiceType() { return voiceType; }
        public void setVoiceType(VoiceType voiceType) { this.voiceType = voiceType; }

        public int getSpeed() { return speed; }
        public void setSpeed(int speed) { this.speed = speed; }

        public int getVolume() { return volume; }
        public void setVolume(int volume) { this.volume = volume; }

        public int getPitch() { return pitch; }
        public void setPitch(int pitch) { this.pitch = pitch; }

        public String getAudioFormat() { return audioFormat; }
        public void setAudioFormat(String audioFormat) { this.audioFormat = audioFormat; }

        public int getSampleRate() { return sampleRate; }
        public void setSampleRate(int sampleRate) { this.sampleRate = sampleRate; }
    }

    // 合成结果
    public static class TtsResult {
        private boolean success;
        private String filePath;
        private String errorMessage;
        private long audioDuration; // 音频时长(ms)

        public TtsResult(boolean success, String filePath, String errorMessage) {
            this.success = success;
            this.filePath = filePath;
            this.errorMessage = errorMessage;
        }

        // getters
        public boolean isSuccess() { return success; }
        public String getFilePath() { return filePath; }
        public String getErrorMessage() { return errorMessage; }
        public long getAudioDuration() { return audioDuration; }
        public void setAudioDuration(long audioDuration) { this.audioDuration = audioDuration; }
    }

    /**
     * 文本转语音合成
     * @param text 要合成的文本
     * @param outputDir 输出目录
     * @param config 合成配置
     * @return 合成结果
     */
    public TtsResult textToSpeech(String text, String outputDir, TtsConfig config) {
        return textToSpeech(text, outputDir, "", config);
    }

    /**
     * 文本转语音合成（指定文件名）
     * @param text 要合成的文本
     * @param outputDir 输出目录
     * @param fileName 输出文件名（不含扩展名）
     * @param config 合成配置
     * @return 合成结果
     */
    public TtsResult textToSpeech(String text, String outputDir, String fileName, TtsConfig config) {
        if (text == null || text.trim().isEmpty()) {
            return new TtsResult(false, null, "合成文本不能为空");
        }

        if (config == null) {
            config = new TtsConfig(); // 使用默认配置
        }

        // 生成输出文件路径
        String filePath = outputDir + File.separator + fileName + ".mp3";
        File outputFile = new File(filePath);

        try {
            // 确保输出目录存在
            File dir = new File(outputDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }

            // 执行合成
            return executeTts(text, outputFile, config);

        } catch (Exception e) {
            return new TtsResult(false, null, "合成失败: " + e.getMessage());
        }
    }

    /**
     * 批量文本转语音合成
     * @param texts 文本列表
     * @param outputDir 输出目录
     * @param config 合成配置
     * @return 合成结果列表
     */
    public List<TtsResult> batchTextToSpeech(List<String> texts, String outputDir, TtsConfig config) {
        List<TtsResult> results = new ArrayList<>();

        for (int i = 0; i < texts.size(); i++) {
            String text = texts.get(i);
            String fileName = "tts_batch_" + System.currentTimeMillis() + "_" + i;
            TtsResult result = textToSpeech(text, outputDir, fileName, config);
            results.add(result);

            // 避免请求过于频繁，添加短暂延迟
            if (i < texts.size() - 1) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }

        return results;
    }

    /**
     * 执行TTS合成
     */
    private TtsResult executeTts(String text, File outputFile, TtsConfig config) {
        CountDownLatch latch = new CountDownLatch(1);
        TtsResultWrapper resultWrapper = new TtsResultWrapper();

        try (FileOutputStream fileOutputStream = new FileOutputStream(outputFile)) {
            // 获取认证URL
            String authUrl = getAuthUrl(HOST_URL, xfApiConfig.getApiKey(), xfApiConfig.getApiSecret());
            OkHttpClient client = new OkHttpClient.Builder()
                    .connectTimeout(30, TimeUnit.SECONDS)
                    .readTimeout(60, TimeUnit.SECONDS)
                    .build();

            System.out.println("语音合成，拼接url = ");
            // 转换为WebSocket URL
            String wsUrl = authUrl.replace("http://", "ws://").replace("https://", "wss://");

            Request request = new Request.Builder().url(wsUrl).build();

            // 创建WebSocket监听器
            WebSocketListener listener = new WebSocketListener() {
                @Override
                public void onOpen(WebSocket webSocket, Response response) {
                    System.out.println("语音合成，发送请求 = " + text);
                    // 发送合成请求
                    JsonObject requestData = buildRequestData(text, config);
                    webSocket.send(requestData.toString());
                }

                @Override
                public void onMessage(WebSocket webSocket, String text) {
                    try {
                        handleResponse(text, fileOutputStream, resultWrapper);
                    } catch (Exception e) {
                        resultWrapper.setError("处理响应失败: " + e.getMessage());
                        latch.countDown();
                    }
                }

                @Override
                public void onMessage(WebSocket webSocket, ByteString bytes) {
                    // 处理二进制消息（如果有）
                }

                @Override
                public void onClosing(WebSocket webSocket, int code, String reason) {
                    // System.out.println("WebSocket关闭中: " + reason);
                }

                @Override
                public void onClosed(WebSocket webSocket, int code, String reason) {
                    latch.countDown();
                }

                @Override
                public void onFailure(WebSocket webSocket, Throwable t, Response response) {
                    resultWrapper.setError("WebSocket连接失败: " + t.getMessage());
                    latch.countDown();
                }
            };

            client.newWebSocket(request, listener);

            // 等待合成完成（最多等待2分钟）
            boolean completed = latch.await(2, TimeUnit.MINUTES);

            if (!completed) {
                return new TtsResult(false, null, "合成超时");
            }

            if (resultWrapper.hasError()) {
                return new TtsResult(false, null, resultWrapper.getError());
            }

            // 计算音频时长（估算：按字符数*0.4秒计算）
            long estimatedDuration = (long) (text.length() * 400);
            TtsResult result = new TtsResult(true, outputFile.getAbsolutePath(), null);
            result.setAudioDuration(estimatedDuration);

            System.out.println("result = " + result.toString());

            return result;

        } catch (Exception e) {
            return new TtsResult(false, null, "合成异常: " + e.getMessage());
        }
    }

    /**
     * 构建请求数据
     */
    private JsonObject buildRequestData(String text, TtsConfig config) {
        JsonObject requestData = new JsonObject();

        // Header
        JsonObject header = new JsonObject();
        header.addProperty("app_id", xfApiConfig.getAppId());
        header.addProperty("status", 2); // 一次性发送，使用状态2

        // Parameter
        JsonObject parameter = new JsonObject();
        JsonObject tts = new JsonObject();

        // TTS参数
        tts.addProperty("vcn", config.getVoiceType().getCode());
        tts.addProperty("speed", config.getSpeed());
        tts.addProperty("volume", config.getVolume());
        tts.addProperty("pitch", config.getPitch());
        tts.addProperty("bgs", 0);
        tts.addProperty("reg", 0);
        tts.addProperty("rdn", 0);
        tts.addProperty("rhy", 0);

        // 音频参数
        JsonObject audio = new JsonObject();
        audio.addProperty("encoding", config.getAudioFormat());
        audio.addProperty("sample_rate", config.getSampleRate());
        audio.addProperty("channels", 1);
        audio.addProperty("bit_depth", 16);
        audio.addProperty("frame_size", 0);

        tts.add("audio", audio);
        parameter.add("tts", tts);

        // Payload
        JsonObject payload = new JsonObject();
        JsonObject textPayload = new JsonObject();

        textPayload.addProperty("encoding", "utf8");
        textPayload.addProperty("compress", "raw");
        textPayload.addProperty("format", "json");
        textPayload.addProperty("status", 2);
        textPayload.addProperty("seq", 0);

        try {
            textPayload.addProperty("text", Base64.getEncoder().encodeToString(text.getBytes("utf8")));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("文本编码失败", e);
        }

        payload.add("text", textPayload);

        // 组合请求数据
        requestData.add("header", header);
        requestData.add("parameter", parameter);
        requestData.add("payload", payload);

        return requestData;
    }

    /**
     * 处理响应
     */
    private void handleResponse(String responseText, FileOutputStream outputStream,
                                TtsResultWrapper resultWrapper) throws IOException {
        JsonResponse response = gson.fromJson(responseText, JsonResponse.class);

        System.out.println("语音合成，x相应 = " + response.header.code + response.header.status);
        if (response.header.code != 0) {
            System.out.println("合成错误，错误码: " + response.header.code + ", sid: " + response.header.sid + response.header.toString() + response.payload.toString());
            return;
        }

        // 处理音频数据
        if (response.payload != null && response.payload.audio != null && response.payload.audio.audio != null) {
            byte[] audioData = Base64.getDecoder().decode(response.payload.audio.audio);
            outputStream.write(audioData);
            outputStream.flush();
        }

        // 检查是否合成完成
        if (response.header.status == 2) {
            // 合成完成
            resultWrapper.setCompleted(true);
        }
    }

    /**
     * 签名鉴权
     */
    private String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {
        URL url = new URL(hostUrl);
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());

        StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n")
                .append("date: ").append(date).append("\n")
                .append("GET ").append(url.getPath()).append(" HTTP/1.1");

        Charset charset = Charset.forName("UTF-8");
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256");
        mac.init(spec);

        byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));
        String sha = Base64.getEncoder().encodeToString(hexDigits);

        String authorization = String.format("hmac username=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",
                apiKey, "hmac-sha256", "host date request-line", sha);

        HttpUrl httpUrl = HttpUrl.parse("https://" + url.getHost() + url.getPath()).newBuilder()
                .addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(charset)))
                .addQueryParameter("date", date)
                .addQueryParameter("host", url.getHost())
                .build();

        return httpUrl.toString();
    }

    // 内部类：响应包装器
    private static class TtsResultWrapper {
        private boolean completed = false;
        private String error = null;

        public boolean isCompleted() { return completed; }
        public void setCompleted(boolean completed) { this.completed = completed; }

        public boolean hasError() { return error != null; }
        public String getError() { return error; }
        public void setError(String error) { this.error = error; }
    }

    // 内部类：响应结构
    private static class JsonResponse {
        ResponseHeader header;
        ResponsePayload payload;
    }

    private static class ResponseHeader {
        int code;
        String sid;
        int status;
    }

    private static class ResponsePayload {
        ResponseAudio audio;
    }

    private static class ResponseAudio {
        String audio;
        int seq;
    }
}
